package com.icinfo.cloud.provider.punish.strategy.document.util;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.icinfo.cloud.provider.common.enums.DocumentTemplateTypeEnum;
import com.icinfo.cloud.provider.punish.document.DocumentFieldCustomConverter;
import com.icinfo.cloud.provider.punish.document.annotations.DocumentParamConvert;
import com.icinfo.cloud.provider.punish.strategy.document.BaseDocumentParam;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * 文书参数转换工具类
 *
 * @author Junfeng.Chen
 * @date 2024/1/15 9:16
 **/
public class DocumentParamUtil {
    private DocumentParamUtil() {

    }

    /**
     * 转换窄幅字段到宽幅
     *
     * @param params           文书参数map
     * @param paramEntityClass 文书参数对象类
     */
    public static void convertNarrowToStandard(Map<String, Object> params, Class<? extends BaseDocumentParam> paramEntityClass) {
        BaseDocumentParam paramEntity = ReflectUtil.newInstance(paramEntityClass);
        paramEntity.fillFieldByParams(DocumentTemplateTypeEnum.NARROW_TEMPLATE, params);
        fieldLoop(paramEntity, context -> {
            DocumentParamConvert documentParamConvert = context.getConvert();
            String narrowField = documentParamConvert.narrow();
            String standardField = documentParamConvert.standard();
            //因为在循环处理时可能会根据params处理复杂的自定义转换，在此步骤时不移除参数
            convertParamAndFillMap(params, context.getParamEntity(), context.getField(), narrowField, standardField);
        });
        //统一移除参数
        fieldLoop(paramEntity, context -> {
            DocumentParamConvert documentParamConvert = context.getConvert();
            String narrowField = documentParamConvert.narrow();
            String standardField = documentParamConvert.standard();
            if (StrUtil.equals(narrowField, standardField)) {
                //相等则不需要移除
                return;
            }
            params.remove(narrowField);
        });
    }

    /**
     * 转换宽幅到窄幅
     *
     * @param params           文书参数
     * @param paramEntityClass 文书参数对象
     */
    public static void convertStandardToNarrow(Map<String, Object> params, Class<? extends BaseDocumentParam> paramEntityClass) {
        BaseDocumentParam paramEntity = ReflectUtil.newInstance(paramEntityClass);
        paramEntity.fillFieldByParams(DocumentTemplateTypeEnum.STANDARD_TEMPLATE, params);
        fieldLoop(paramEntity, context -> {
            DocumentParamConvert documentParamConvert = context.getConvert();
            String narrowField = documentParamConvert.narrow();
            String standardField = documentParamConvert.standard();
            //因为在循环处理时可能会根据params处理复杂的自定义转换，在此步骤时不移除参数
            convertParamAndFillMap(params, context.getParamEntity(), context.getField(), standardField, narrowField);
        });
        //统一移除参数
        fieldLoop(paramEntity, context -> {
            DocumentParamConvert documentParamConvert = context.getConvert();
            String narrowField = documentParamConvert.narrow();
            String standardField = documentParamConvert.standard();
            if (StrUtil.equals(narrowField, standardField)) {
                //相等则不需要移除
                return;
            }
            params.remove(standardField);
        });
    }

    /**
     * 获取文书参数
     *
     * @param paramEntity  文书参数对象
     * @param getFieldName 获取字段名称
     * @return
     */
    public static Map<String, Object> getDocumentParams(BaseDocumentParam paramEntity, Function<DocumentParamConvert, String> getFieldName) {
        Map<String, Object> params = new HashMap<>();
        //字段转换集合容器
        List<FieldLoopContext> needConvertFieldList = new LinkedList<>();
        //循环处理参数
        fieldLoop(paramEntity, context -> {
            String fieldName = getFieldName.apply(context.getConvert());
            if (StrUtil.isEmpty(fieldName)) {
                return;
            }
            //如果为function则处理function
            if (DocumentFieldCustomConverter.class.isAssignableFrom(context.getField().getType())) {
                needConvertFieldList.add(context);
                return;
            }
            params.put(fieldName, ReflectUtil.getFieldValue(paramEntity, context.getField()));
        });
        //循环处理需要转换的字段
        for (FieldLoopContext context : needConvertFieldList) {
            if (!DocumentFieldCustomConverter.class.isAssignableFrom(context.getField().getType())) {
                continue;
            }
            DocumentFieldCustomConverter converter = (DocumentFieldCustomConverter) ReflectUtil.getFieldValue(paramEntity, context.getField());
            //获取转换后的值
            params.put(getFieldName.apply(context.getConvert()), converter.convert(params));
        }

        return params;
    }

    /**
     * 循环对象字段进行处理
     *
     * @param paramEntity 对象
     * @param hook        处理的钩子
     */
    private static void fieldLoop(BaseDocumentParam paramEntity, Consumer<FieldLoopContext> hook) {
        Field[] fields = ReflectUtil.getFields(paramEntity.getClass());
        for (Field field : fields) {
            DocumentParamConvert convert = field.getAnnotation(DocumentParamConvert.class);
            if (Objects.isNull(convert)) {
                continue;
            }
            hook.accept(new FieldLoopContext(field, convert, paramEntity));
        }
    }

    /**
     * 转换参数并填充map
     *
     * @param params      参数容器
     * @param paramEntity 文书参数对象
     * @param sourceField 来源字段
     * @param targetField 目标字段
     */
    private static void convertParamAndFillMap(Map<String, Object> params, BaseDocumentParam paramEntity,
                                               Field field, String sourceField, String targetField) {
        // 目标字段为空 或 来源和目标字段名称相同 这些状况都不用处理转换
        if (StrUtil.isEmpty(targetField) || targetField.equals(sourceField)) {
            return;
        }
        //如果为function则处理function
        if (DocumentFieldCustomConverter.class.isAssignableFrom(field.getType())) {
            Object converter = ReflectUtil.getFieldValue(paramEntity, field);
            if (Objects.isNull(converter)) {
                //此处说明该转换未初始化不转换
                return;
            }
            DocumentFieldCustomConverter documentFieldCustomConverter = (DocumentFieldCustomConverter) converter;
            //获取转换后的值
            params.put(targetField, documentFieldCustomConverter.convert(params));
            return;
        }
        //新增字段
        params.put(targetField, params.get(sourceField));
    }

    /**
     * 字段循环上下文
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    private static class FieldLoopContext {
        /**
         * 当前字段
         */
        private Field field;

        /**
         * 当前字段文书参数转换注解
         */
        private DocumentParamConvert convert;

        /**
         * 文书参数对象
         */
        private BaseDocumentParam paramEntity;
    }
}
